/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.nodes;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeEvent;
import java.util.*;
import org.openide.util.NbBundle;
/** Support for creation of property sets. Allows easy
* addition, modification, and deletion of properties. Also
* permits listening on changes of contained properties.
*
* @author Jaroslav Tulach, Dafe Simonek
*/
public final class Sheet extends Object {
/** list of sets (Sheet.Set)
* @associates Set*/
private ArrayList sets;
/** array of sets */
private Node.PropertySet[] array;
/** support for changes */
private PropertyChangeSupport supp = new PropertyChangeSupport (this);
/** change listener that is attached to each set added to this object */
private PropertyChangeListener propL = new PropertyChangeListener () {
public void propertyChange (PropertyChangeEvent ev) {
supp.firePropertyChange (null, null, null);
}
};
/** Name for regular Bean property set. */
public static final String PROPERTIES = "properties"; // NOI18N
/** Name for expert Bean property set. */
public static final String EXPERT = "expert"; // NOI18N
/** Default constructor.
*/
public Sheet() {
this (new ArrayList (2));
}
/** Copy constrcutor.
* @param ar array to use
*/
private Sheet(ArrayList ar) {
sets = ar;
}
/** Obtain the array of property sets.
* @return the array
*/
public final Node.PropertySet[] toArray () {
Node.PropertySet[] l = array;
if (l != null) return l;
synchronized (this) {
if (array != null) return array;
array = new Node.PropertySet [sets.size ()];
sets.toArray (array);
return array;
}
}
/** Create a deep copy of the sheet. Listeners are not copied.
* @return the cloned object */
public synchronized Sheet cloneSheet () {
int len = sets.size ();
ArrayList l = new ArrayList (len);
for (int i = 0; i < len; i++) {
l.add (((Set)sets.get (i)).cloneSet ());
}
return new Sheet (l);
}
/** Find the property set with a given name.
* @param name name of the set
* @return the property set, or <code>null</code> if no such set exists
*/
public synchronized Set get (String name) {
int indx = findIndex (name);
return indx == -1 ? null : (Set)sets.get (indx);
}
/** Add a property set. If the set does not yet exist in the sheet,
* inserts a new set with the implied name. Otherwise the old set is replaced
* by the new one.
*
* @param set to add
* @return the previous set with the same name, or <code>null</code> if this is a fresh insertion
*/
public synchronized Set put (Set set) {
int indx = findIndex (set.getName ());
Set removed;
if (indx == -1) {
sets.add (set);
removed = null;
} else {
removed = (Set)sets.set (indx, set);
}
// listeners
set.addPropertyChangeListener (propL);
if (removed != null) {
set.removePropertyChangeListener (propL);
}
refresh ();
return removed;
}
/** Remove a property set from the sheet.
* @param set name of set to remove
* @return removed set, or <code>null</code> if the set could not be found
*/
public synchronized Set remove (String set) {
int indx = findIndex (set);
if (indx != -1) {
Set s = (Set)sets.remove (indx);
s.removePropertyChangeListener (propL);
refresh ();
return s;
} else {
return null;
}
}
/** Convenience method to create new sheet with only one empty set, named {@link #PROPERTIES}.
* Display name and hint are settable via the appropriate bundle.
*
* @return a new sheet with default property set
*/
public static Sheet createDefault () {
Sheet newSheet = new Sheet();
// create default property set
newSheet.put(createPropertiesSet ());
return newSheet;
}
/** Convenience method to create new sheet set named {@link #PROPERTIES}.
*
* @return a new properties sheet set
*/
public static Sheet.Set createPropertiesSet () {
Sheet.Set ps = new Sheet.Set ();
ps.setName(PROPERTIES);
ps.setDisplayName(Node.getString("Properties"));
ps.setShortDescription(Node.getString("HINT_Properties"));
return ps;
}
/** Convenience method to create new sheet set named {@link #EXPERT}.
*
* @return a new expert properties sheet set
*/
public static Sheet.Set createExpertSet () {
Sheet.Set ps = new Sheet.Set ();
ps.setName(EXPERT);
ps.setDisplayName(Node.getString("Expert"));
ps.setShortDescription(Node.getString("HINT_Expert"));
return ps;
}
/** Add a change listener.
* @param l the listener */
public void addPropertyChangeListener (PropertyChangeListener l) {
supp.addPropertyChangeListener (l);
}
/** Remove a change listener.
* @param l the listener */
public void removePropertyChangeListener (PropertyChangeListener l) {
supp.removePropertyChangeListener (l);
}
/** Finds index for property set for given name.
* @param name of the property
* @return the index or -1 if not found
*/
private int findIndex (String name) {
int s = sets.size ();
for (int i = 0; i < s; i++) {
Node.PropertySet p = (Node.PropertySet)sets.get (i);
if (p.getName ().equals (name)) {
return i;
}
}
return -1;
}
/** Refreshes and fire info about the set
*/
private void refresh () {
array = null;
supp.firePropertyChange (null, null, null);
}
/********* Inner classes **********/
/** A set of Bean properties.
*/
public static final class Set extends Node.PropertySet {
/** list of properties (Node.Property)
* @associates Property*/
private ArrayList props;
/** array of properties */
private Node.Property[] array;
/** change listeners listening on this set */
private PropertyChangeSupport supp = new PropertyChangeSupport (this);
/** Default constructor.
*/
public Set () {
this (new ArrayList ());
}
/** @param al array list to use for this property set
*/
private Set (ArrayList al) {
props = al;
}
/** Clone the property set.
* @return the clone
*/
public synchronized Set cloneSet () {
return new Set ((ArrayList)props.clone ());
}
/** Get a property by name.
* @param name name of the property
* @return the first property in the list that has this name, <code>null</code> if not found
*/
public Node.Property get (String name) {
int indx = findIndex (name);
return indx == -1 ? null : (Node.Property)props.get (indx);
}
/** Get all properties in this set.
* @return the properties
*/
public Node.Property[] getProperties () {
Node.Property[] l = array;
if (l != null) return l;
synchronized (this) {
if (array != null) return array;
array = new Node.Property [props.size ()];
props.toArray (array);
return array;
}
}
/** Add a property to this set, replacing any old one with the same name.
* @param p the property to add
* @return the property with the same name that was replaced, or <code>null</code> for a fresh insertion
*/
public synchronized Node.Property put (Node.Property p) {
int indx = findIndex (p.getName ());
Node.Property removed;
if (indx != -1) {
// replaces the original one
removed = (Node.Property)props.set (indx, p);
} else {
// adds this to the end
props.add (p);
removed = null;
}
// clears computed array and fires into about change of properties
refresh ();
return removed;
}
/** Add several properties to this set, replacing old ones with the same names.
*
* @param ar properties to add
*/
public synchronized void put (Node.Property[] ar) {
for (int i = 0; i < ar.length; i++) {
Node.Property p = ar[i];
p = ar[i];
int indx = findIndex (p.getName ());
if (indx != -1) {
// replaces the original one
props.set (indx, p);
} else {
// adds this to the end
props.add (p);
}
}
// clears computed array and fires into about change of properties
refresh ();
}
/** Remove a property from the set.
* @param name name of the property to remove
* @return the removed property, or <code>null</code> if it was not there to begin with
*/
public synchronized Node.Property remove (String name) {
int indx = findIndex (name);
if (indx != -1) {
try {
return (Node.Property)props.remove (indx);
} finally {
// clears computed array and fires into about change of properties
refresh ();
}
} else {
return null;
}
}
/** Add a property change listener.
* @param l the listener to add */
public void addPropertyChangeListener (PropertyChangeListener l) {
supp.addPropertyChangeListener (l);
}
/** Remove a property change listener.
* @param l the listener to remove */
public void removePropertyChangeListener (PropertyChangeListener l) {
supp.removePropertyChangeListener (l);
}
/** Finds index for property with specified name.
* @param name of the property
* @return the index or -1 if not found
*/
private int findIndex (String name) {
int s = props.size ();
for (int i = 0; i < s; i++) {
Node.Property p = (Node.Property)props.get (i);
if (p.getName ().equals (name)) {
return i;
}
}
return -1;
}
/** Notifies change of properties.
*/
private void refresh () {
array = null;
supp.firePropertyChange (null, null, null);
}
} // end of Set
}
/*
* Log
* 6 Gandalf 1.5 1/12/00 Jesse Glick NOI18N
* 5 Gandalf 1.4 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 4 Gandalf 1.3 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 3 Gandalf 1.2 5/8/99 Ian Formanek Added convenience methods
* createPropertiesSet and createExpertSet
* 2 Gandalf 1.1 3/17/99 Jesse Glick [JavaDoc]
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
*/